<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { arr2Tree, deepClone } from '@/utils'
import { findMenus, insertMenu, updateMenu, deleteMenu } from '@/api/permission'
import { ElMessage } from 'element-plus'
import { useMenusStore } from '@/store/menus'
import * as Icons from '@element-plus/icons-vue'
import SytTable from '@/components/SytTable/SytTable.vue'

const tableThs = ref([
  { title: '路由名', dataIndex: 'name' },
  { title: '路由路径', dataIndex: 'path' },
  { title: '组件路径', dataIndex: 'component' },
  { title: '菜单名', dataIndex: 'meta.title' },
  { title: '显示菜单', dataIndex: 'meta.showLink' }
])
const menusStore = useMenusStore()
let treeData = ref([])
let loading = ref(true)

let dialogFormVisible = ref(false)
let ruleFormRef = ref(null)
let dialogOpenType = ref('')

const rules = ref({
  name: [
    {
      required: true,
      message: '请输入路由名',
      trigger: 'blur'
    }
  ],
  path: [
    {
      required: true,
      message: '请输入路由路径',
      trigger: 'blur'
    }
  ],
  component: [
    {
      required: true,
      message: '请输入组件路径',
      trigger: 'blur'
    }
  ],
  ['meta.title']: [
    {
      required: true,
      message: '请输入菜单名',
      trigger: 'blur'
    }
  ],
  ['meta.showLink']: [
    {
      required: true,
      message: '显示菜单',
      trigger: 'change'
    }
  ]
})

//dialog data
let rawDialogData = () => ({
  pid: '',
  path: '',
  name: '',
  component: '', // /src/views...
  meta: {
    icon: '',
    title: '',
    showLink: true
  }
})

let dialogData = ref(rawDialogData())

const initData = async () => {
  await findMenus().then((res) => {
    if (res.code === 200) {
      res.data.forEach((menu) => {
        menu.iconComponent = Icons[menu.meta?.icon]
      })

      treeData.value = arr2Tree(res.data)

      menusStore.SAVE_MENUS(res.data)
    }
  })

  loading.value = false
}

const openDialogByInsert = () => {
  dialogOpenType.value = '添加'
  dialogFormVisible.value = true

  dialogData.value = rawDialogData()
}

const openDialogByEdit = (row) => {
  dialogOpenType.value = '编辑'
  dialogFormVisible.value = true
  dialogData.value = deepClone(row)
}

const addRole = async () => {
  let data = Object.assign({}, dialogData.value)
  insertMenu(data).then((res) => {
    if (res.code == 200) {
      ElMessage({ type: 'success', message: '添加成功' })
      initData()
    }
  })
}
const setRole = async () => {
  let data: any = Object.assign({}, dialogData.value)
  updateMenu(data).then((res) => {
    if (res.code == 200) {
      ElMessage({ type: 'success', message: '编辑成功' })
      initData()
    }
  })
}

const removeRole = (row) => {
  if (row._id) {
    deleteMenu({ _id: row._id }).then((res) => {
      if (res.code == 200) {
        ElMessage({ type: 'success', message: '删除成功' })
        initData()
      }
    })
  } else ElMessage({ type: 'error', message: '不存在的_id' })
}

const submitForm = (formEl) => {
  if (!formEl) return
  formEl.validate((valid) => {
    if (valid) {
      if (dialogOpenType.value === '添加') addRole()
      else setRole()

      dialogFormVisible.value = false
    } else {
      console.log('验证失败!')
    }
  })
}

onMounted(() => {
  initData()
})
</script>

<template>
  <div class="container">
    <div class="tools">
      <el-button @click="openDialogByInsert">添加菜单</el-button>
    </div>

    <SytTable :columns="tableThs" :data="treeData">
      <template #operations="{ row }">
        <el-icon class="icon" color="#0af" @click="openDialogByEdit(row)"><Edit /></el-icon>
        <el-popconfirm title="确定删除?" @confirm="removeRole(row)">
          <template #reference>
            <el-icon class="icon" color="#f00"><Delete /></el-icon>
          </template>
        </el-popconfirm>
      </template>
    </SytTable>
    <el-dialog v-model="dialogFormVisible" :title="dialogOpenType" width="350px">
      <el-form
        ref="ruleFormRef"
        :model="dialogData"
        :rules="rules"
        size="large"
        class="w-full"
        label-width="auto"
      >
        <el-form-item label="路由名" prop="name">
          <el-input v-model="dialogData.name" placeholder="路由名" />
        </el-form-item>
        <el-form-item label="路由路径" prop="path">
          <el-input v-model="dialogData.path" placeholder="需包含上级菜单的路径" />
        </el-form-item>
        <el-form-item label="组件路径" prop="component">
          <el-input v-model="dialogData.component" placeholder="/src/views/**.vue" />
        </el-form-item>
        <el-form-item label="菜单名" prop="meta.title">
          <el-input v-model="dialogData.meta.title" placeholder="菜单名" />
        </el-form-item>
        <el-form-item label="显示菜单" prop="meta.showLink">
          <el-switch v-model="dialogData.meta.showLink" />
        </el-form-item>
        <el-form-item label="菜单图标" prop="meta.icon">
          <el-popover title="图标" :width="350" placement="top" trigger="click">
            <el-icon
              v-for="(icon, name) in Icons"
              :key="name"
              class="icon"
              :size="15"
              @click="dialogData.meta.icon = name"
            >
              <component :is="icon"></component>
            </el-icon>
            <template #reference>
              <el-icon v-if="dialogData.meta.icon" :size="20" class="icon">
                <component :is="dialogData.meta.icon"></component>
              </el-icon>
              <span v-else class="icon-select-text">选择图标</span>
            </template>
          </el-popover>
        </el-form-item>
        <el-form-item label="上级菜单">
          <el-tree-select
            v-model="dialogData.pid"
            :data="treeData"
            :props="{ label: (data) => data.meta.title, value: 'id' }"
            check-strictly
            :render-after-expand="false"
            clearable
            style="width: 240px"
          />
        </el-form-item>
        <el-form-item>
          <el-button class="w-full" type="primary" @click="submitForm(ruleFormRef)">
            保存
          </el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<style scoped>
.container {
  width: 100%;
  height: 100%;
}

.tools {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 10px;
}

.tree {
  max-width: 600px;
  font-size: 16px;
  border: 1px solid #eef;
  padding: 10px;
  border-radius: 10px;
}

.icon {
  cursor: pointer;
  margin-left: 5px;
  font-size: 15px;
}

.icon-select-text {
  cursor: pointer;
  color: var(--el-text-color-placeholder);
}
</style>
